#include "cv.h"
#include "highgui.h"
#include "location.h"
#include "util.h"

char Resize(IplImage* pSrc, IplImage** pDst, long h, long w)
{
	if (!pSrc)
	{
		return 1;
	}
	else
	{
		*pDst = cvCreateImage(cvSize(h, w), pSrc->depth, pSrc->nChannels);
		cvResize(pSrc, *pDst);
		return 0;
	}
}

char PreProcess(IplImage* pSrc, IplImage** pDst)
{
	if (!pSrc)
	{
		return 1;
	}
	else
	{
		IplImage* pDst1 = cvCreateImage(cvGetSize(pSrc),IPL_DEPTH_8U,1);
		cvSmooth(pSrc, pDst1, CV_MEDIAN, 3, 0, 0, 0);            //使用3*3模板进行中值滤波,去除噪声
		Diff(pDst1, pDst);
		//*pDst = pDst1;
		cvReleaseImage(&pDst1);//函数cvReleaseImage销毁已定义的IplImage指针变量，释放占用内存空间
		return 0;
	}
}

char Diff(IplImage* pSrc, IplImage** pDst)
{
	if (!pSrc)
	{
		return 1;
	}
	else
	{
		*pDst = cvCreateImage(cvGetSize(pSrc),IPL_DEPTH_8U,1);
		for (long i = 0; i < pSrc->height; i++)
		{
			for (long j = 0; j < pSrc->width - 9; j++)
			{
				long sum = 0;
				for (long k = j; k < j + 9; k++)
				{
					sum += (uchar)(pSrc->imageData + pSrc->widthStep * i)[k];
				}
				long value = (uchar)(pSrc->imageData + pSrc->widthStep * i)[j] - sum / 9;
				cvSetReal2D(*pDst, i, j, value);
			}
		}
		return 0;
	}
}
char Edge(IplImage* pSrc, IplImage** pDst)
{
	if (!pSrc)
	{
		return 1;
	}
	else
	{
		IplImage* pTempImg = cvCreateImage(cvGetSize(pSrc),IPL_DEPTH_16S,1);
		*pDst = cvCreateImage(cvGetSize(pSrc),IPL_DEPTH_8U,1);

		cvSobel(pSrc, pTempImg, 1,0,3);           //首先进行Sobel变换
		cvConvertScaleAbs(pTempImg,*pDst,1,0);    //对值域进行缩放

		cvReleaseImage( &pTempImg );
		return 0;
	}
}

char Hist(IplImage* pSrc, long* pHist)
{
	if (!pSrc)
	{
		return 1;
	}
	else if(!pHist)
	{
		return 2;
	}
	else
	{
		memset(pHist, 0, 256 * sizeof(long));
		long h = pSrc->height;
		long w = pSrc->width;

		//对每个灰度级进行直方图累加
		for (long i = 0; i < h; i++)
		{
			for (long j = 0; j < w; j++)
			{
				uchar k = (uchar)(pSrc->imageData + pSrc->widthStep * i)[j];    //找出(j,i)的像素值
				pHist[k]++;
			}
		}
		return 0;
	}
}

long Threshold(long* pHist, long length)
{
	if (!pHist)
	{
		return -1;
	}
	else
	{
		//若i以及i往后的9个点的累加值均小于100,则将第一次出现的这样的i作为阈值灰度值
		long thresh = -1;
		long flag = 0;
		//从20开始循环,因为前面的累加值都很大,这样可以减少循环次数
		for (long i = 20; i < length - 10; i++)
		{
			flag = 0;
			for (long j = i; j < i+10; j++)
			{
				if (pHist[j] < 100)
				{
					flag++;
				}
			}
			if (flag == 10)
			{
				thresh = i;
				break;
			}
		}
		return thresh;
	}
}

char Binary(IplImage* pSrc, IplImage** pDst)
{
	long* pHist = (long*)malloc(256 * sizeof(long));
	Hist(pSrc, pHist);                                             //求直方图
	long thresh = Threshold(pHist, 256);                           //求阈值
	*pDst = cvCreateImage(cvGetSize(pSrc),IPL_DEPTH_8U,1);
	//printf("%d\n", thresh);
	cvThreshold(pSrc, *pDst, thresh, 255, CV_THRESH_BINARY);       //二值化
	free(pHist);
	return 0;
}

char CreateHopMap(IplImage* pSrc, long* pHopMap)
{
	if (!pSrc)
	{
		return 1;
	}
	else if (!pHopMap)
	{
		return 2;
	}
	else
	{
		long h = pSrc->height;
		long w = pSrc->width;

		memset(pHopMap, 0, (h * w) * sizeof(long));

		//将原本是二维数组的跳变表放到一维数组中,这样便于传递参数.跳变表是行主序
		for (long y = 0; y < h; y++)
		{
			for (long x = 0; x < w - 1; x++)
			{
				uchar k1 = (uchar)(pSrc->imageData + pSrc->widthStep * y)[x];
				uchar k2 = (uchar)(pSrc->imageData + pSrc->widthStep * y)[x + 1];
				if (k1 == 0 && k2 == 255)                  //如果(x,y)的值为0而(x+1,y)的值为1,则跳变值为1
				{
					pHopMap[y * w + x] = 1;
				}
			}
		}
		return 0;
	}
}

char GetRowHops(long* pHopMap, long h, long w, long* pRowHops)
{
	if (!pHopMap)
	{
		return 1;
	}
	else if (!pRowHops)
	{
		return 2;
	}
	else
	{
	    for (long y = 0; y < h; y++)
		{
			pRowHops[y] = Sum(&pHopMap[y * w], w);             //累加行跳变值
		}
		return 0;
	}
}

char GetCandidatesFromHeight(long* pHopMap, long h, long w, std::list<Box>& blist)
{
	if (!pHopMap)
	{
		return 1;
	}
	else
	{
		long* pRowHops = (long*)malloc(h * sizeof(long));
		GetRowHops(pHopMap, h, w, pRowHops);                            //获得行跳变值
		GetBox(pRowHops, h, 2*Avg(pRowHops, h), 3, blist);            //将行跳变值进行划分
		//for (std::list<struct Box>::iterator iter = blist.begin(); iter != blist.end(); iter++)
		//{
		//	printf("%ld %ld %ld\n", iter->b1, iter->b2, iter->total);
		//}
		for (std::list<struct Box>::iterator iter = blist.begin(); iter != blist.end();)
		{
			if (iter->b2 - iter->b1 >= 75)
			{
				blist.erase(iter++);
			}
			else iter++;
		}
		//求划分后区域跳变值最大值
		long max_total = 0;
		for (std::list<struct Box>::iterator iter = blist.begin(); iter != blist.end(); iter++)
		{
			if (iter->total > max_total)
			{
				max_total = iter->total;
			}
		}

		//将行跳变值小于最大值1/3的和区域高度超过55像素的候选区域排除
		for (std::list<struct Box>::iterator iter = blist.begin(); iter != blist.end();)
		{
			if (iter->total < max_total / 3)
			{
				blist.erase(iter++);
			}
			else iter++;
		}
		//for (std::list<struct Box>::iterator iter = blist.begin(); iter != blist.end(); iter++)
		//{
		//	printf("%ld %ld %ld\n", iter->b1, iter->b2, iter->total);
		//}
		free(pRowHops);
		return 0;
	}
}

char GetBox(long* arr, long length, long thresh, long u, std::list<Box>& blist)
{
	if (!arr)
	{
		return 1;
	}
	else
	{
		long state = 0;
		long b1 = 0;
		long b2 = 0;
		long total = 0;
		long max_total = 0;
		struct Box box;
		box.b1 = -100;
		box.b2 = -100;

		for (long i = 0; i < length; i++)
		{
			switch(state)
			{
			case 0:
				if (arr[i] >= thresh)
				{
					state = 1;
					b1 = i;
				}
				break;
			case 1:
				if (arr[i] < thresh)
				{
					state = 0;
					b2 = i;
					total = Sum(&arr[b1], b2 - b1);
					if (b1 - box.b2 <= u)          //若区域之间的距离小于u,则合并
					{
						blist.pop_back();
						box.b2 = b2;
						box.total += total;
					}
					else
					{
						box.b1 = b1;
						box.b2 = b2;
						box.total = total;
					}
					blist.push_back(box);
				}
			}
		}
		return 0;
	}
}

char GetColumnPixels(IplImage* pSrc, long y1, long y2, long* pColumnPixels)
{
	if (!pSrc)
	{
		return 1;
	}
	else if (!pColumnPixels)
	{
		return 2;
	}
	else
	{
		long w = pSrc->width;
		memset(pColumnPixels, 0, w * sizeof(long));

		//按照宽度序列将像素值累加
		for (long j = 0; j < w; j++)
		{
			for (long i = y1; i < y2; i++)
			{
				uchar k = (uchar)(pSrc->imageData + pSrc->widthStep * i)[j];    //找出(j,i)的像素值
				if (k == 255)
				{
					pColumnPixels[j]++;
				}
			}
		}
		return 0;
	}
}

char GetCandidatesFromWidth(IplImage* pSrc, std::list<Box>& blist, std::list<Rect>& rlist)
{
	if (!pSrc)
	{
		return 1;
	}
	else
	{
		long w = pSrc->width;
		long* pColumnPixels = (long*)malloc(w * sizeof(long));

		//对blist中的每一个候选高度区域,都进行筛选
		for (std::list<struct Box>::iterator iter = blist.begin(); iter != blist.end(); iter++)
		{
			GetColumnPixels(pSrc, iter->b1, iter->b2, pColumnPixels);           //获得列累加像素值
			//for (int i = 0; i < 512; i++)
			//{
			//	printf("%ld ", pColumnPixels[i]);
			//}
			std::list<Box> tlist;
			GetBox(pColumnPixels, w, 3 * Avg(pColumnPixels, w), 20, tlist);     //将列累加像素值按照指定的阈值和合并值进行划分,将结果保存在临时列表tlist中
			//for (std::list<struct Box>::iterator iter1 = tlist.begin(); iter1 != tlist.end(); iter1++)
			//{
			//	printf("%d %d %d\n", iter1->b1, iter1->b2, iter1->total);
			//}

			for (std::list<struct Box>::iterator iter1 = tlist.begin(); iter1 != tlist.end();)
			{
				if (iter1->b2 - iter1->b1 >= 160 || iter1->b2 - iter1->b1 <= 70)
				{
					tlist.erase(iter1++);
				}
				else iter1++;
			}
			//求候选区域中的列累加像素值的最大值
			long max_total = 0;
			for (std::list<struct Box>::iterator iter1 = tlist.begin(); iter1 != tlist.end(); iter1++)
			{
				if (iter1->total > max_total)
				{
					max_total = iter1->total;
				}
			}

			//将候选区域中的列累加像素值小于最大值1/3的以及宽度不在(70,160)范围内的区域排除
			for (std::list<struct Box>::iterator iter1 = tlist.begin(); iter1 != tlist.end();)
			{
				if (iter1->total < max_total / 3)
				{
					tlist.erase(iter1++);
				}
				else iter1++;
			}

			//将筛选后的候选区域加入到rlist中
			for (std::list<struct Box>::iterator iter1 = tlist.begin(); iter1 != tlist.end(); iter1++)
			{
				Rect r;
				r.x1 = iter1->b1;
				r.y1 = iter->b1;
				r.x2 = iter1->b2;
				r.y2 = iter->b2;
				rlist.push_back(r);
				//printf("%ld %ld %ld %ld\n", r.x1, r.x2, r.y1, r.y2);
			}
		}
		free(pColumnPixels);
		return 0;
	}
}

char GetRectHops(long* pHopMap, long h ,long w, Rect& rect)
{
	if (!pHopMap)
	{
		return 1;
	}
	else
	{
		long total = 0;
		long x1 = rect.x1;
		long y1 = rect.y1;
		long x2 = rect.x2;
		long y2 = rect.y2;

		//对跳变值进行累加,将累加值保存在rect.total中
		for (long i = y1; i < y2; i++)
		{
			for (long j = x1; j < x2; j++)
			{
				total += pHopMap[i * w + j];
			}
		}
		rect.total = total;
		return 0;
	}

}

void Select(std::list<Rect>& rlist, long* pHopMap, Rect& rect)
{
	long total = 0;
	//将跳变累加值最大的区域作为真实区域
	for (std::list<struct Rect>::iterator iter = rlist.begin(); iter != rlist.end();)
	{
		GetRectHops(pHopMap, 512, 512, *iter);     //获得区域的跳变累加值
		if (total > iter->total)
		{
			iter++;
		}
		else
		{
			total = iter->total;
			rect = *iter;
			iter++;
		}
	}
	//printf("%ld %ld %ld %ld\n", rect.x1, rect.y1, rect.x2, rect.y2);
}
